package com.example.myapplication.round;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.FrameLayout;

import com.example.myapplication.R;

import java.util.Arrays;

/**
 * <p>圆角或圆形裁剪的 FrameLayout，裁剪画布实现我暂时想不到方法能消除边缘锯齿，所以只能用 PorterDuffXfermode</p>
 *
 * @author 黎曼
 * date 2020/7/5
 */
public class RoundFrameLayout2 extends FrameLayout {
    private final int INVALID_VALUE = -1;
    //整个 View 的圆角信息都在这个对象里面
    private RoundStatus mRoundStatus;
    //圆角效果主要存在这个路径里
    private Path mPath;
    //圆角矩形描述
    private RectF mRectF;
    //画笔
    private Paint mPaint;

    public RoundFrameLayout2(@NonNull Context context) {
        this(context, null);
    }

    public RoundFrameLayout2(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RoundFrameLayout2(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.RoundFrameLayout2,
                0, 0);

        try {
            //ViewGroup 整体的圆角半径
            float radius;
            float topLeftRadius;
            float topRightRadius;
            float bottomLeftRadius;
            float bottomRightRadius;
            if (typedArray.hasValue(R.styleable.RoundFrameLayout2_rd_radius)
                    && typedArray.peekValue(R.styleable.RoundFrameLayout2_rd_radius).type == TypedValue.TYPE_DIMENSION) {
                radius = typedArray.getDimension(R.styleable.RoundFrameLayout2_rd_radius, 0);
            } else {//TypedValue.TYPE_INT_DEC
                radius = typedArray.getInteger(R.styleable.RoundFrameLayout2_rd_radius, 0);
            }
            topLeftRadius = typedArray.getDimension(R.styleable.RoundFrameLayout2_rd_top_left_radius, INVALID_VALUE);
            topRightRadius = typedArray.getDimension(R.styleable.RoundFrameLayout2_rd_top_right_radius, INVALID_VALUE);
            bottomRightRadius = typedArray.getDimension(R.styleable.RoundFrameLayout2_rd_bottom_right_radius, INVALID_VALUE);
            bottomLeftRadius = typedArray.getDimension(R.styleable.RoundFrameLayout2_rd_bottom_left_radius, INVALID_VALUE);

            mRoundStatus = new RoundStatusImpl.RoundStatusBuilder()
                    .setMRadius(radius)
                    .setMTopLeftRadius(topLeftRadius)
                    .setMTopRightRadius(topRightRadius)
                    .setMBottomRightRadius(bottomRightRadius)
                    .setMBottomLeftRadius(bottomLeftRadius)
                    .build();
        } finally {
            //注意资源回收
            typedArray.recycle();
        }
        init();
    }

    private void init() {
        setWillNotDraw(false);
        //关闭硬件加速
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);

        mPath = new Path();
        mRectF = new RectF();
        fillRadius();

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (w > 0) {
            mPath.reset();
            //Path 的填充模式为反奇偶规则
            mPath.setFillType(Path.FillType.INVERSE_EVEN_ODD);
            if (getRadius() < 0) {
                mPath.addCircle((float) (w / 2), (float) (h / 2), (float) (Math.min(w, h) / 2), Path.Direction.CW);
            } else {
                mRectF.set(0, 0, w, h);
                mPath.addRoundRect(mRectF, getRadiusList(), Path.Direction.CW);
            }
        }
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        canvas.drawPath(mPath, mPaint);
    }

    //绘制刷新时的必要逻辑
    private void update() {
        mPath.reset();
        //Path 的填充模式为反奇偶规则
        mPath.setFillType(Path.FillType.INVERSE_EVEN_ODD);
        if (getRadius() < 0) {
            mPath.addCircle((float) (getWidth() / 2), (float) (getHeight() / 2), (float) (Math.min(getWidth(), getHeight()) / 2), Path.Direction.CW);
        } else {
            mPath.addRoundRect(mRectF, getRadiusList(), Path.Direction.CW);
        }
        invalidate();
    }

    public void fillRadius() {
        mRoundStatus.fillRadius();
    }

    public void setRadius(float radius) {
        mRoundStatus.setRadius(radius);
        update();
    }

    public void setTopLeftRadius(float topLeftRadius) {
        mRoundStatus.setTopLeftRadius(topLeftRadius);
        update();
    }

    public void setTopRightRadius(float topRightRadius) {
        mRoundStatus.setTopRightRadius(topRightRadius);
        update();
    }

    public void setBottomRightRadius(float bottomRightRadius) {
        mRoundStatus.setBottomRightRadius(bottomRightRadius);
        update();
    }

    public void setBottomLeftRadius(float bottomLeftRadius) {
        mRoundStatus.setTopLeftRadius(bottomLeftRadius);
        update();
    }

    public float getRadius() {
        return mRoundStatus.getRadius();
    }

    public float getTopLeftRadius() {
        return mRoundStatus.getTopLeftRadius();
    }

    public float getTopRightRadius() {
        return mRoundStatus.getTopRightRadius();
    }

    public float getBottomRightRadius() {
        return mRoundStatus.getBottomRightRadius();
    }

    public float getBottomLeftRadius() {
        return mRoundStatus.getTopLeftRadius();
    }

    public float[] getRadiusList() {
        return mRoundStatus.getRadiusList();
    }

    public interface RoundStatus {
        //设置所有圆角的半径,，再分别设置每个单个圆角的半径
        void fillRadius();

        //设置所有圆角的半径
        void setRadius(float radius);

        //设置左上角圆角半径
        void setTopLeftRadius(float topLeftRadius);

        //设置右上角圆角半径
        void setTopRightRadius(float topRightRadius);

        //设置右下角圆角半径
        void setBottomRightRadius(float bottomRightRadius);

        //设置左下角圆角半径
        void setBottomLeftRadius(float bottomLeftRadius);

        //获取所有圆角的半径
        float getRadius();

        //获取左上角圆角半径
        float getTopLeftRadius();

        //获取右上角圆角半径
        float getTopRightRadius();

        //获取右下角圆角半径
        float getBottomRightRadius();

        //获取左下角圆角半径
        float getBottomLeftRadius();

        //获取记录各个角的圆角半径的数组
        float[] getRadiusList();
    }

    public static class RoundStatusImpl implements RoundStatus {

        //ViewGroup 整体的圆角半径
        private float mRadius;
        private float mTopLeftRadius;
        private float mTopRightRadius;
        private float mBottomLeftRadius;
        private float mBottomRightRadius;

        private float[] mRadiusList = new float[8];

        @Override
        public void fillRadius() {
            setRadius(mRadius);

            setTopLeftRadius(mTopLeftRadius);
            setTopRightRadius(mTopRightRadius);
            setBottomRightRadius(mBottomRightRadius);
            setBottomLeftRadius(mBottomLeftRadius);
        }

        @Override
        public void setRadius(float radius) {
            mRadius = radius;
            Arrays.fill(mRadiusList, mRadius);
        }

        @Override
        public void setTopLeftRadius(float topLeftRadius) {
            mTopLeftRadius = topLeftRadius;
            if (mTopLeftRadius >= 0) {
                Arrays.fill(mRadiusList, 0, 2, mTopLeftRadius);
            }
        }

        @Override
        public void setTopRightRadius(float topRightRadius) {
            mTopRightRadius = topRightRadius;
            if (mTopRightRadius >= 0) {
                Arrays.fill(mRadiusList, 2, 4, mTopRightRadius);
            }
        }

        @Override
        public void setBottomRightRadius(float bottomRightRadius) {
            mBottomRightRadius = bottomRightRadius;
            if (mBottomRightRadius >= 0) {
                Arrays.fill(mRadiusList, 4, 6, mBottomRightRadius);
            }
        }

        @Override
        public void setBottomLeftRadius(float bottomLeftRadius) {
            mBottomLeftRadius = bottomLeftRadius;
            if (mBottomLeftRadius >= 0) {
                Arrays.fill(mRadiusList, 6, 8, mBottomLeftRadius);
            }
        }

        @Override
        public float getRadius() {
            return mRadius;
        }

        @Override
        public float getTopLeftRadius() {
            return mTopLeftRadius;
        }

        @Override
        public float getTopRightRadius() {
            return mTopRightRadius;
        }

        @Override
        public float getBottomRightRadius() {
            return mBottomRightRadius;
        }

        @Override
        public float getBottomLeftRadius() {
            return mBottomLeftRadius;
        }

        @Override
        public float[] getRadiusList() {
            return mRadiusList;
        }

        //RoundStatus 的生成器
        public static final class RoundStatusBuilder {
            //ViewGroup 整体的圆角半径
            private float mRadius;
            private float mTopLeftRadius;
            private float mTopRightRadius;
            private float mBottomLeftRadius;
            private float mBottomRightRadius;

            public RoundStatusBuilder() {
            }

            public RoundStatusBuilder setMRadius(float mRadius) {
                this.mRadius = mRadius;
                return this;
            }

            public RoundStatusBuilder setMTopLeftRadius(float mTopLeftRadius) {
                this.mTopLeftRadius = mTopLeftRadius;
                return this;
            }

            public RoundStatusBuilder setMTopRightRadius(float mTopRightRadius) {
                this.mTopRightRadius = mTopRightRadius;
                return this;
            }

            public RoundStatusBuilder setMBottomLeftRadius(float mBottomLeftRadius) {
                this.mBottomLeftRadius = mBottomLeftRadius;
                return this;
            }

            public RoundStatusBuilder setMBottomRightRadius(float mBottomRightRadius) {
                this.mBottomRightRadius = mBottomRightRadius;
                return this;
            }

            public RoundStatusImpl build() {
                RoundStatusImpl roundStatusImpl = new RoundStatusImpl();
                roundStatusImpl.mRadius = this.mRadius;
                roundStatusImpl.mBottomRightRadius = this.mBottomRightRadius;
                roundStatusImpl.mTopLeftRadius = this.mTopLeftRadius;
                roundStatusImpl.mTopRightRadius = this.mTopRightRadius;
                roundStatusImpl.mBottomLeftRadius = this.mBottomLeftRadius;
                return roundStatusImpl;
            }
        }
    }
}
